package com.hjx.config;

import com.hjx.security.JwtAuthTokenFilter;
import com.hjx.security.MyUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;
import java.util.Arrays;

/**
 * <p>Title:</p>
 * <p>Description:</p>
 *
 * @author hjx
 * @date 2020/6/10 - 8:51
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    JwtAuthTokenFilter jwtAuthTokenFilter;
    @Resource
    MyUserDetailsService myUserDetailsService;
//    authorizeRequests()和 anyRequest().authenticated()就会要求所有进入应用的请求都要进行认证
//    access(String) 如果给定的SpEL表达式计算结果为true，就允许访问
//    anonymous() 允许匿名用户访问
//    authenticated() 允许认证的用户进行访问
//    denyAll() 无条件拒绝所有访问
//    fullyAuthenticated() 如果用户是完整认证的话（不是通过Remember-me功能认证的），就允许访问
//    hasAuthority(String) 如果用户具备给定权限的话就允许访问
//    hasAnyAuthority(String…)如果用户具备给定权限中的某一个的话，就允许访问
//    hasRole(String) 如果用户具备给定角色(用户组)的话,就允许访问/
//    hasAnyRole(String…) 如果用户具有给定角色(用户组)中的一个的话,允许访问.
//    hasIpAddress(String 如果请求来自给定ip地址的话,就允许访问.
//    not() 对其他访问结果求反.
//    permitAll() 无条件允许访问
//    rememberMe() 如果用户是通过Remember-me功能认证的，就允许访问


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
//            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
//            .ignoringAntMatchers("/authentication")
            .cors()
                .and()
            .addFilterBefore(jwtAuthTokenFilter, UsernamePasswordAuthenticationFilter.class)
            .authorizeRequests()
            .antMatchers("/authentication","/refreshToken").permitAll()
                //除了配置的请求路径可以直接放行 其他的所有请求都要经过rbacService的鉴权才能通过
            .anyRequest().access("@rbacService.hasPermission(request,authentication)")
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService)
                .passwordEncoder(passwordEncoder());
    }
    //密码加密
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    //跨域配置
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE"));
        configuration.setAllowCredentials(true);
        configuration.setMaxAge(3600L);
        configuration.applyPermitDefaultValues();
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}
